package dao;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.sql.DataSource;

import org.apache.tomcat.dbcp.dbcp.DelegatingPreparedStatement;

import model.Shain;

import exception.BusinessException;
import exception.SystemException;

/**
 * 社員情報アクセスクラス
 * 社員情報テーブルへの検索、登録、更新、削除メソッドを提供する
 * @author kenta
 *
 */
public class DaoShain {
	//DBとのコネクション
	private Connection db;
	//ステートメント
	private PreparedStatement ps;

	/**
	 * コンストラクタ。Context.xmlで定義したデータソースを用い、
	 * データベースとのコネクションを確立する
	 */
	public DaoShain() throws SystemException{
		try{
			Context context = new InitialContext();
			DataSource ds = (DataSource)context.lookup("java:comp/env/jdbc/ojt");
			this.db = ds.getConnection();
		}
		catch (Exception e){
			e.printStackTrace();
			throw new SystemException(e.getMessage());
		}
	}

	/**
	 * 社員番号とパスワードでAND検索し、一致する社員が存在するか確認するメソッド
	 * @param 社員情報モデルクラス
	 * @return true 存在する false 存在しない
	 * @throws SystemExcepton システム例外
	 * @throws BusinessException 一致する社員が存在しない
	 */
	public boolean isExistShain(Shain shain) throws SystemException,BusinessException {
		//照合結果
		boolean result = false;
		//テーブルの検索結果
		ResultSet rs;

		try{
			//SQLを作成
			this.ps = db.prepareStatement(
				"SELECT first_name, last_name from t_shain WHERE shain_no = ? AND password = ?");
			this.ps.setString(1, shain.shain_no);
			this.ps.setString(2, shain.password);

			//SQLを実行
			rs = ps.executeQuery();

			//検索結果が1件以外の場合、認証エラー
			rs.next();
			if(rs.getRow() != 1){
				throw new BusinessException("社員番号、もしくはパスワードに誤りがあります");
			}
			//社員情報モデルクラスに姓、名を格納
			else{
				shain.first_name = rs.getString("first_name");
				shain.last_name = rs.getString("last_name");
				result = true;
			}
		}
		catch(SQLException e){
			e.printStackTrace();
			throw new SystemException(e.getMessage());
		}
		catch(NullPointerException e){
			e.printStackTrace();
			throw new SystemException(e.getMessage());
		}
		return result;
	}
	
	/**
	 * 社員番号で社員情報テーブルを検索し、一致する社員がいるかどうか確認するメソッド
	 * @param String 社員番号
	 * @throws SystemException システム例外
	 * @throws BusinessException 業務例外：社員番号がすでに存在する
	 */
	public boolean isNotExistShain(String shain_no) throws SystemException,BusinessException {
		//照合結果
		boolean result = true;
		//テーブルの検索結果
		ResultSet rs;

		try{
			//SQLを作成
			this.ps = db.prepareStatement("SELECT first_name, last_name FROM t_shain WHERE shain_no = ?");
			this.ps.setString(1, shain_no);

			//SQLを実行
			rs = ps.executeQuery();

			//検索結果が0件以外の場合、認証エラー
			rs.next();
			if(rs.getRow() != 0){
				throw new BusinessException("社員番号がすでに存在します");
			}
		}
		catch(SQLException e){
			e.printStackTrace();
			throw new SystemException(e.getMessage());
		}
		catch(NullPointerException e){
			e.printStackTrace();
			throw new SystemException(e.getMessage());
		}
		return result;
	}

	/**
	 * 社員登録メソッド。受け取った社員情報で、
	 * 社員情報テーブルへの登録を行う
	 * @param shain 社員情報
	 * @throws SystemException システム例外
	 * @throws BusinessException 業務例外：登録に失敗
	 */
	public void insertNewShain(Shain shain)throws SystemException, BusinessException{
		//登録した行数
		int affectedRow =0;
		//SQLを作成
		try{
			this.ps = db.prepareStatement(
					"INSERT into t_shain " +
					"(shain_no, password, first_name, last_name, sex, section_code, enter_date, e_mail)" +
					"VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
			this.ps.setString(1, shain.shain_no);
			this.ps.setString(2, shain.password);
			this.ps.setString(3, shain.first_name);
			this.ps.setString(4, shain.last_name);
			this.ps.setString(5, shain.sex);
			this.ps.setString(6, shain.section_code);
			this.ps.setString(7, shain.enter_date);
			this.ps.setString(8, shain.e_mail);

			//SQLを実行
			affectedRow = this.ps.executeUpdate();
			
			//登録件数が1以外の場合、業務例外をスロー
			if (affectedRow != 1){
				throw new BusinessException ("登録に失敗しました");
			}
		}
		//例外が発生した場合、システム例外をスローする
		catch(SQLException e){
			throw new SystemException(e.getMessage());
		}
	}

	/**
	 * 社員情報検索メソッド
	 * @param Shain 社員情報モデルクラス
	 * @return result
	 * @throws SystemException システム例外
	 * @throws BusinessException 業務例外：該当社員なし
	 */
	public ArrayList<Shain> searchShain(Shain shain)throws SystemException,BusinessException {
		// 検索結果
		ArrayList<Shain> searchResult = new ArrayList<Shain>();
		// 結果セット
		ResultSet rs;
		//SQLを作成する
		StringBuffer sb = new StringBuffer("SELECT shain_no, first_name, last_name, sex, enter_date, section_code, e_mail " +
				"FROM t_shain " +
				"WHERE");
		//社員番号が空でない場合、検索条件に加える
		if(shain.shain_no.equals("") != true){
			sb.append(" shain_no = '" + shain.shain_no + "'");
		}
		else{
			sb.append(" shain_no <> ''");
		}
		//性別が空でない場合、検索条件に加える
		if(shain.sex.equals("") != true){
			sb.append(" AND sex = '" + shain.sex + "'");
		}
		//部門が空でない場合、検索条件に加える
		if(shain.section_code.equals("") != true){
			sb.append(" AND section_code = '" + shain.section_code + "'");
		}
		//入社年月日(From)が空でない場合、検索条件に加える
		if(shain.enter_date_from.equals("") != true){
			sb.append(" AND enter_date >= '" + shain.enter_date_from + "'");
		}
		//入社年月日(To)が空でない場合、検索条件に加える
		if(shain.enter_date_to.equals("") != true){
			sb.append(" AND enter_date <= '" + shain.enter_date_to + "'");
		}
		//ORDER BY を追加
		sb.append(" ORDER BY shain_no ASC");

		//sqlをStringに返還
		String sql = sb.toString();

		try{
			//SQLを作成
			this.ps = this.db.prepareStatement(sql);
			//TODO 後で消す　debug
			System.out.println("Degug:"+((DelegatingPreparedStatement)ps).getDelegate().toString());
			//SQLを実行
			rs = ps.executeQuery();

			//結果セットから社員情報を取得し、ArrayList<Shain>に値を格納
			while(rs.next()){
				Shain s = new Shain();
				s.shain_no = rs.getString("shain_no");
				s.first_name = rs.getString("first_name");
				s.last_name = rs.getString("last_name");
				s.sex = rs.getString("sex");
				s.enter_date = rs.getString("enter_date");
				s.section_code = rs.getString("section_code");
				s.e_mail = rs.getString("e_mail");

				searchResult.add(s);
			}
			//検索結果が０件の場合、業務例外をスロー
			if(searchResult.size() == 0){
				BusinessException be = new BusinessException();
				be.setErrorMessage("一致する社員がいませんでした");
				throw be;
			}
		}
		//例外が発生した場合、システム例外をスローする
		catch (SQLException e){
			throw new SystemException(e.getMessage());
		}

		return searchResult;
	}

	/**
	 * 社員情報削除メソッド
	 * 入力された社員番号の社員情報を削除する
	 * @param shain_no
	 * @throws SystemException システム例外
	 * @throws BusinessException 該当する社員が存在しない
	 */
	public void deleteShain(String shain_no) throws SystemException, BusinessException{
		//削除された行数
		int affectedRow=0;

		try{
		//SQLの作成
		this.ps = this.db.prepareStatement(
				"DELETE FROM t_shain " +
				"WHERE shain_no = ? ");
		this.ps.setString(1, shain_no);

		//TODO 後で消す　debug
		System.out.println("Degug:"+((DelegatingPreparedStatement)ps).getDelegate().toString());
		//SQLの実行
		affectedRow = this.ps.executeUpdate();



		//削除された行数が1以外の場合、業務例外をスロー
		if(affectedRow != 1){
			throw new BusinessException("存在しない社員番号です");
		}
		}
		catch (SQLException e){
			throw new SystemException(e.getMessage());
		}
	}

	/**
	 * 社員番号から、社員詳細情報を検索し、社員の詳細情報を返すメソッド
	 * @param shain_no
	 * @return Shain 社員情報モデルクラス
	 * @throws SystemException システム例外
	 * @throws BusinessException 業務例外 該当社員なし
	 */
	public Shain seachShainDetail(String shain_no)throws SystemException,BusinessException {
		// 結果セット
		ResultSet rs;
		//社員情報モデルクラス
		Shain shain = new Shain();
		try{
			//SQLの作成
			this.ps = this.db.prepareStatement(
				"SELECT shain_no, password, first_name, last_name, sex, section_code, enter_date, e_mail " +
				"FROM t_shain " +
				"WHERE shain_no = ? ");
			this.ps.setString(1, shain_no);

			//TODO 後で消す　debug
			System.out.println("Degug:"+((DelegatingPreparedStatement)ps).getDelegate().toString());
			//SQLの実行
			rs = this.ps.executeQuery();

			//社員番号に一致する社員情報が存在しない場合、業務例外をスロー
			if(!rs.next()){
				throw new BusinessException("存在しない社員番号です");
			}
			else{
				shain.shain_no = rs.getString("shain_no");
				shain.password = rs.getString("password");
				shain.first_name = rs.getString("first_name");
				shain.last_name = rs.getString("last_name");
				shain.sex = rs.getString("sex");
				shain.section_code = rs.getString("section_code");
				shain.enter_date = rs.getString("enter_date");
				shain.e_mail = rs.getString("e_mail");
			}
		}
		catch (SQLException e){
			throw new SystemException(e.getMessage());
		}
		return shain;
	}

	/**
	 * 社員情報更新メソッド。変更前の社員番号をWHERE区に指定し
	 * その社員情報を更新する
	 * @param Shain 社員情報クラスメソッド
	 * @throws SysytemException システム例外
	 * @throws BusinessException 業務例外
	 */
	public void updateShain(Shain shain)throws SystemException, BusinessException {
		//更新した行の数
		int count=0;
		//SQLを作成
		try{
			this.ps = db.prepareStatement(
					"UPDATE t_shain " +
					"SET shain_no = ?, " +
					"first_name = ?, " +
					"last_name = ?, " +
					"sex = ?, " +
					"section_code = ?, " +
					"enter_date = ?, " +
					"e_mail = ? " +
					"WHERE shain_no = ?");
			this.ps.setString(1, shain.shain_no);
			this.ps.setString(2, shain.first_name);
			this.ps.setString(3, shain.last_name);
			this.ps.setString(4, shain.sex);
			this.ps.setString(5, shain.section_code);
			this.ps.setString(6, shain.enter_date);
			this.ps.setString(7, shain.e_mail);
			this.ps.setString(8, shain.shain_no_old);

			//DEBUG TODO 後で消す
			System.out.println(((DelegatingPreparedStatement)ps).getDelegate().toString());
			//SQLを実行
			count = this.ps.executeUpdate();

			//更新した行数が1以外の場合、業務例外をスロー
			if(count !=1){
				throw new BusinessException("不正な処理が行われました");
			}
		}
		//例外が発生した場合、システム例外をスローする
		catch(SQLException e){
			throw new SystemException(e.getMessage());
		}
	}

	/**
	 * コネクションをクローズするメソッド
	 * @throws SystemException
	 *
	 */
	public void closeConnection() throws SystemException{

		//コネクションがcloseされていなかったら、closeする
		try{
			if(!this.db.isClosed()){
				this.db.close();
			}
		}
		catch (SQLException e){
			e.printStackTrace();
			throw new SystemException(e.getMessage());
		}
	}
}

